﻿#include "player.h"

Player player;

Player::Player()
{
	dummy_player = new Enemy;
}

Player::~Player()
{
	delete dummy_player;
}

void Player::LoadPlayer(CL_String name, CL_GraphicContext &gc, CL_ResourceManager &resources)
{
	direction = CL_Vec2<float>(0,0);
	focused = false;
	spellcard_activated = false;
	shot_gaining = 0;
	dead = false;
	invicible = 0;
	spellcard = 0;
	player_time = 0;
	focused_time = 0;
	sidemove_time = 0;
	time_from_last_shot = 0;
	time_from_last_autoshot1 = 0;
	shooting_time = 0;
	score = 0;
	points = 0;
	graze = 0;
	power = 10;
	lives = 3;
	spells = 2;
	hp = 5000;
	joystick_moved = 0;
	moving_aside = 0;
	last_move_direction = 0;
	is_bomb = false;
	wind_activated = false;
	bomb_time = 0;
	wind_time = 0;
	wind = 100.0f;

	CL_DomElement element = resources.get_resource(name).get_element();
	std::map<std::string, CL_String> params;
	std::vector<CL_DomNode> param_nodes = element.select_nodes("param");
	for (size_t p_index = 0; p_index < param_nodes.size(); p_index++)
		params[param_nodes[p_index].to_element().get_attribute("name").c_str()] = param_nodes[p_index].to_element().get_text();

	normal_speed = CL_StringHelp::text_to_float(params["normal_speed"]);
	focused_speed = CL_StringHelp::text_to_float(params["focused_speed"]);
	spellcard_active_speed = CL_StringHelp::text_to_float(params["spellcard_active_speed"]);
	collision_size = CL_StringHelp::text_to_float(params["hitbox"]);
	bonus_collision_size = CL_StringHelp::text_to_float(params["bonus_collision"]);
	bonus_attract_collision = CL_StringHelp::text_to_float(params["bonus_attract_collision"]);
	bonus_attract_focus_collision = CL_StringHelp::text_to_float(params["bonus_attract_focus_collision"]);
	graze_collision_size = CL_StringHelp::text_to_float(params["graze_size"]);
	shooting_speed = CL_StringHelp::text_to_float(params["shooting_speed"]);
	focus_speed = CL_StringHelp::text_to_float(params["focus_speed"]);
	bullet_alpha = CL_StringHelp::text_to_float(params["bullet_alpha"]);
	death_time = CL_StringHelp::text_to_float(params["death_time"]);
	invicible_time = CL_StringHelp::text_to_int(params["invicible_time"]);
	base_hp = CL_StringHelp::text_to_int(params["base_hp"]);
	graze_score = CL_StringHelp::text_to_int(params["graze_score"]);

	wind_radius = CL_StringHelp::text_to_float(params["wind_radius"]);
	wind_speed = CL_StringHelp::text_to_float(params["wind_speed"]);
	wind_accel = CL_StringHelp::text_to_float(params["wind_accel"]);

	wind_gain_speed = CL_StringHelp::text_to_float(params["wind_gain_speed"]);
	wind_shot_gain = CL_StringHelp::text_to_float(params["wind_shot_gain"]);
	wind_kill_gain = CL_StringHelp::text_to_float(params["wind_kill_gain"]);
	wind_graze_gain = CL_StringHelp::text_to_float(params["wind_graze_gain"]);

	time_to_activate_wind = CL_StringHelp::text_to_float(params["time_to_activate_wind"]);
	time_wind_activation = CL_StringHelp::text_to_float(params["time_wind_activation"]);
	wind_max_blow_time = CL_StringHelp::text_to_float(params["wind_max_blow_time"]);

	spellcard_min_duration = CL_StringHelp::text_to_int(params["spellcard_min_duration"]);
	spellcard_max_duration = CL_StringHelp::text_to_int(params["spellcard_max_duration"]);
	start_power = CL_StringHelp::text_to_int(params["start_power"]);
	bomb_duration = CL_StringHelp::text_to_float(params["bomb_duration"]);
	bomb_damage = CL_StringHelp::text_to_float(params["bomb_damage"]);

	shot1_interval = CL_StringHelp::text_to_float(params["shot1_interval"]);
	shot1_speed = CL_StringHelp::text_to_float(params["shot1_speed"]);
	shot1_bullets = CL_StringHelp::text_to_int(params["shot1_bullets"]);
	shot1_damage = CL_StringHelp::text_to_int(params["shot1_damage"]);
	shot1_focus_damage = CL_StringHelp::text_to_int(params["shot1_focus_damage"]);

	shot2_interval = CL_StringHelp::text_to_float(params["shot2_interval"]);
	shot2_speed = CL_StringHelp::text_to_float(params["shot2_speed"]);
	shot2_damage = CL_StringHelp::text_to_int(params["shot2_damage"]);
	shot2_startpower = CL_StringHelp::text_to_int(params["shot2_startpower"]);
	shot2_steppower = CL_StringHelp::text_to_int(params["shot2_steppower"]);

	shot3_interval = CL_StringHelp::text_to_float(params["shot3_interval"]);
	shot3_speed = CL_StringHelp::text_to_float(params["shot3_speed"]);
	shot3_angle_speed = CL_StringHelp::text_to_float(params["shot3_angle_speed"]);
	shot3_accel_time = CL_StringHelp::text_to_float(params["shot3_accel_time"]);
	shot3_speed_delta = CL_StringHelp::text_to_float(params["shot3_speed_delta"]);
	shot3_bullets = CL_StringHelp::text_to_int(params["shot3_bullets"]);
	shot3_damage = CL_StringHelp::text_to_int(params["shot3_damage"]);

	shot4_interval = CL_StringHelp::text_to_float(params["shot4_interval"]);
	shot4_speed = CL_StringHelp::text_to_float(params["shot4_speed"]);
	shot4_shooting_speed = CL_StringHelp::text_to_float(params["shot4_shooting_speed"]);
	shot4_angle_speed = CL_StringHelp::text_to_float(params["shot4_angle_speed"]);
	shot4_change_angle = CL_StringHelp::text_to_float(params["shot4_change_angle"]);
	shot4_speed_delta = CL_StringHelp::text_to_float(params["shot4_speed_delta"]);
	shot4_radius = CL_StringHelp::text_to_float(params["shot4_radius"]);
	shot4_bullets = CL_StringHelp::text_to_int(params["shot4_bullets"]);
	shot4_damage = CL_StringHelp::text_to_int(params["shot4_damage"]);

	player_sprite = CL_Sprite(gc, params["player_sprite"], &resources);
	focus_sprite = CL_Sprite(gc, params["focus_sprite"], &resources);
	wind_sprite = CL_Sprite(gc, params["wind_sprite"], &resources);
	wind_font_sprite = CL_Sprite(gc, params["wind_font_sprite"], &resources);
	dead_splash = sprite_container.GetSprite("fairy_splash");
	magic_flash = sprite_container.GetSprite("magic_flash");
	visible_size = CL_Size(player_sprite.get_width(), player_sprite.get_height());

	spell_time = spellcard_min_duration;
	spell_time_remaining = spellcard_min_duration;
}

void Player::Update(float time)
{
	player_time += time;
	wind += wind_gain_speed * time;
	if (wind > 100.0f)
		wind = 100.0f;
	// Время бессмертия
	if (invicible)
	{
		invicible -= (int)time;
		if (invicible < 0)
			invicible = 0;
	}
	// Начальный ввод игока
	if (player_time < death_time * 2)
	{
		dead_time += time;
		if (player_time > death_time)
		{
			position.x = global_state.render_field.left + global_state.render_field.get_width() / 2.0f;
			position.y = global_state.render_field.bottom + 48.0f - (global_state.render_field.get_height() / 7.0f) * ((player_time - death_time) / death_time);
		}
		else
		{
			position = CL_Vec2<float>(global_state.render_field.left + global_state.render_field.get_width() / 2.0f, global_state.render_field.bottom + 48.0f);
		}
		return;
	}
	// Пациент жив или мёртв?
	if (dead)
	{
		dead_time += time;
		return;
	}
	// Обработка времени ветра
	if (wind_activated)
	{
		wind_time += time;
	}
	// Ввод игрока
	direction.x = 0;
	direction.y = 0;
	focused = false;
	shooting = false;
	rapid = false;
	bomb_trigger = false;
	moving_aside = 0;
	process_keyboard();
	if (joystick_available)
		process_joystick();
	
	// Отключить стрельбу во время диалогов
	if (global_state.game_dialog)
	{
		shooting = false;
		rapid = false;
		bomb_trigger = false;
	}

	moving_aside = (int)(direction.x * 1.5f);
	if (last_move_direction != moving_aside)
		sidemove_time = 0;
	if (moving_aside)
		sidemove_time += time;
	last_move_direction = moving_aside;
	
	// Отключить стрельбу на первые 0.5 секунд после начала уровня для оприятствивания рестарта
	//if (global_state.time_processed < 500)
	//	shooting = false;

	// Движения
	prev_position = position;
	if (is_bomb)
	{
		position += direction * spellcard_active_speed * time;
	}
	else if (focused)
	{
		position += direction * focused_speed * time;
		focused_time += (int)time;
	}
	else
	{
		position += direction * normal_speed * time;
		if (focused_time)
		{
			if (focused_time > 200)
				focused_time = 200;
			focused_time -= (int)time;
			if (focused_time < 0)
				focused_time = 0;
		}
	}
	if ((position.x + 10) > global_state.render_field.right)
		position.x = global_state.render_field.right - 10;
	if ((position.x - 10) < global_state.render_field.left)
		position.x = global_state.render_field.left + 10;
	if ((position.y + 12) > global_state.render_field.bottom)
		position.y = global_state.render_field.bottom - 12;
	if ((position.y - 24) < global_state.render_field.top)
		position.y = global_state.render_field.top + 24;
	
	// Активация бомбы
	if (bomb_trigger && !is_bomb && (spells > 0))
	{
		is_bomb = true;
		bomb_time = 0;
		spells--;
		invicible = (int)(bomb_duration * 1.5f);
		if (global_state.game_boss_spellcard_active)
			spell_failed = 1;
	}

	if (is_bomb)
	{
		shooting = false;
		rapid = false;
		bomb_time += time;
		if (bomb_time > bomb_duration)
			is_bomb = false;
		else
			BlowBomb(time);
	}

	// Стрельба и ветер
	bool shot_now = false;
	time_from_last_shot += time;
	if (shooting)
	{
		shot_gaining += time;
		if (!wind_trigger)
		{
			// ветер ещё не заряжен
			if (shot_gaining < time_to_activate_wind)
			{
				shot_now = true;
			}
			else if (shot_gaining > (time_to_activate_wind + time_wind_activation) && wind >= 30.0f)
			{
				// зарядили ветер
				wind_trigger = true;
				//smanager.PlaySound("click");
			}
		}
	}
	else
	{
		if (wind_trigger)
		{
			// спускаем ветер
			wind_trigger = false;
			wind_activated = true;
			// заряжаем время и мощность
			wind_blow_time = 0;
			wind_current_radius = wind_radius * (wind / 50.0f);
			wind_to_blow = wind_max_blow_time * (wind / 100.0f);
			wind = 0;
			//smanager.PlaySound("wind");
		}
		if (rapid)
			shot_now = true;
		shot_gaining = 0;
	}

	// Ветер
	if (wind_activated)
	{
		wind_blow_time += time;
		wind_to_blow -= time;
		if (wind_to_blow > 0)
			BlowWind(wind_current_radius, time);
		else
			wind_activated = false;
	}

	// Сама стрельба
	if (shot_now && shooting_speed < time_from_last_shot)
	{
		// nonspell shot
		Shoot(0);
		time_from_last_shot = 0;
	}
}

void Player::UpdateFromReplay(Replay_Frame &rf)
{
	float time = rf.time;
	player_time += time;
	wind += wind_gain_speed * time;
	if (wind > 100.0f)
		wind = 100.0f;
	// Время бессмертия
	if (invicible)
	{
		invicible -= (int)time;
		if (invicible < 0)
			invicible = 0;
	}
	// Начальный ввод игока
	if (player_time < death_time * 2)
	{
		dead_time += time;
		if (player_time > death_time)
		{
			position.x = global_state.render_field.left + global_state.render_field.get_width() / 2.0f;
			position.y = global_state.render_field.bottom + 48.0f - (global_state.render_field.get_height() / 7.0f) * ((player_time - death_time) / death_time);
		}
		else
		{
			position = CL_Vec2<float>(global_state.render_field.left + global_state.render_field.get_width() / 2.0f, global_state.render_field.bottom + 48.0f);
		}
		return;
	}
	// Пациент жив или мёртв?
	if (dead)
	{
		dead_time += time;
		return;
	}
	// Обработка времени ветра
	if (wind_activated)
	{
		wind_time += time;
	}
	// Данные из реплея
	focused = rf.player_focus ? true : false;
	shooting = rf.player_shot ? true : false;
	rapid = rf.player_rapid? true : false;
	bomb_trigger = rf.player_spellcard_trigger ? true : false;
	focus_angle = CL_Angle(rf.player_a, cl_radians);
	
	// Отключить стрельбу во время диалогов
	if (global_state.game_dialog)
	{
		shooting = false;
		rapid = false;
		bomb_trigger = false;
	}

	// Отключить стрельбу на первые 0.5 секунд после начала уровня для оприятствивания рестарта
	//if (global_state.time_processed < 500)
	//	shooting = false;

	// Движения
	prev_position = position;
	position.x = rf.player_x;
	position.y = rf.player_y;
	direction = (position - prev_position).normalize();

	moving_aside = (int)(direction.x * 1.5f);
	if (last_move_direction != moving_aside)
		sidemove_time = 0;
	if (moving_aside)
		sidemove_time += time;
	last_move_direction = moving_aside;
	
	if ((position.x + 10) > global_state.render_field.right)
		position.x = global_state.render_field.right - 10;
	if ((position.x - 10) < global_state.render_field.left)
		position.x = global_state.render_field.left + 10;
	if ((position.y + 12) > global_state.render_field.bottom)
		position.y = global_state.render_field.bottom - 12;
	if ((position.y - 24) < global_state.render_field.top)
		position.y = global_state.render_field.top + 24;
	
	// Активация бомбы
	if (bomb_trigger && !is_bomb && (spells > 0))
	{
		is_bomb = true;
		bomb_time = 0;
		spells--;
		invicible = (int)(bomb_duration * 1.5f);
	}

	if (is_bomb)
	{
		shooting = false;
		rapid = false;
		bomb_time += time;
		if (bomb_time > bomb_duration)
			is_bomb = false;
		else
			BlowBomb(time);
	}

	// Стрельба и ветер
	bool shot_now = false;
	time_from_last_shot += time;
	if (shooting)
	{
		shot_gaining += time;
		if (!wind_trigger)
		{
			// ветер ещё не заряжен
			if (shot_gaining < time_to_activate_wind)
			{
				shot_now = true;
			}
			else if (shot_gaining > (time_to_activate_wind + time_wind_activation) && wind >= 30.0f)
			{
				// зарядили ветер
				wind_trigger = true;
				//smanager.PlaySound("click");
			}
		}
	}
	else
	{
		if (wind_trigger)
		{
			// спускаем ветер
			wind_trigger = false;
			wind_activated = true;
			// заряжаем время и мощность
			wind_blow_time = 0;
			wind_current_radius = wind_radius * (wind / 50.0f);
			wind_to_blow = wind_max_blow_time * (wind / 100.0f);
			wind = 0;
			//smanager.PlaySound("wind");
		}
		if (rapid)
			shot_now = true;
		shot_gaining = 0;
	}

	// Ветер
	if (wind_activated)
	{
		wind_blow_time += time;
		wind_to_blow -= time;
		if (wind_to_blow > 0)
			BlowWind(wind_current_radius, time);
		else
			wind_activated = false;
	}

	// Сама стрельба
	if (shot_now && shooting_speed < time_from_last_shot)
	{
		// nonspell shot
		Shoot(0);
		time_from_last_shot = 0;
	}
}

void Player::CalculateCollisions()
{
	// Рассчитать столкновения с пулями и противниками
	int damage;
	if (invicible)
	{
		if (bmanager.CollidePlayer())
		{
			// Звук пустой коллизии
			smanager.PlaySound("se_nodamage");
		}
		float col_s = collision_size;
		collision_size = 20;
		emanager.CollidePlayer();
		collision_size = col_s;
		return;
	}
	else
	{
		damage = bmanager.CollidePlayer();
		if (spellcard_activated)
			damage += emanager.CollidePlayer();
		else
			if (!damage)
				damage = emanager.CollidePlayer();
	}
	if (spellcard_activated)
	{
		// Режим спеллкарты - вычесть из жизей
		hp -= damage;
		// Если хп кончилось, выключить спеллкарту
		// ---
	}
	else
	{
		// Обычный режим, попадание влечёт к смерти
		if (damage)
		{
			// запускаем механизм смерти
			// ---
			// перед этим проверка, не включён ли режим автоспелла, когда набрано 8 полных спеллкарт
			// ---
			dead = true;
			dead_time = 0;
			player_time = 0;
			smanager.PlaySound("player_dead");
			// И выкинуть из трупа паверапы
			// --
			return;
		}
	}
}

void Player::BlowWind(float radius, float time)
{
	dummy_player->position = position;
	dummy_player->prev_position = position;
	dummy_player->collision_size = radius;
	bmanager.BlowBullets(dummy_player, time);
}

void Player::BlowBomb(float time)
{
	emanager.BombEnemies(time);
	bmanager.BlowBulletsBomb(time);
}

void Player::Render(CL_GraphicContext &gc)
{
	gc.set_cliprect(global_state.clip_rect);
	if (dead)
	{
		// ошмётки
		float to_scale = 1 + (dead_time / death_time) * 5;
		float to_alpha = (death_time - dead_time) / death_time;
		static const CL_Vec2<float> v1(cos(CL_Angle(-30, cl_degrees).to_radians()), sin(CL_Angle(-30, cl_degrees).to_radians()));
		static const CL_Vec2<float> v2(cos(CL_Angle(222, cl_degrees).to_radians()), sin(CL_Angle(222, cl_degrees).to_radians()));
		static const CL_Vec2<float> v3(cos(CL_Angle(310, cl_degrees).to_radians()), sin(CL_Angle(310, cl_degrees).to_radians()));
		static const CL_Vec2<float> v4(cos(CL_Angle(99, cl_degrees).to_radians()), sin(CL_Angle(99, cl_degrees).to_radians()));
		static const CL_Vec2<float> v5(cos(CL_Angle(170, cl_degrees).to_radians()), sin(CL_Angle(17, cl_degrees).to_radians()));
		if (dead_time < death_time/2)
			player_sprite.draw(gc, prev_position.x, prev_position.y);
		magic_flash->set_frame(rand() % 4);
		magic_flash->set_alpha(to_alpha + 0.5f);
		magic_flash->set_scale(4.0f - to_scale/2.0f, 4.0f - to_scale/2.0f);
		magic_flash->set_alignment(origin_center);
		magic_flash->draw(gc, (prev_position + v1*100*(dead_time / death_time)).x, (prev_position + v1*100*(dead_time / death_time)).y);
		magic_flash->draw(gc, (prev_position + v2*100*(dead_time / death_time)).x, (prev_position + v2*100*(dead_time / death_time)).y);
		magic_flash->draw(gc, (prev_position + v3*100*(dead_time / death_time)).x, (prev_position + v3*100*(dead_time / death_time)).y);
		magic_flash->draw(gc, (prev_position + v4*100*(dead_time / death_time)).x, (prev_position + v4*100*(dead_time / death_time)).y);
		magic_flash->draw(gc, (prev_position + v5*100*(dead_time / death_time)).x, (prev_position + v5*100*(dead_time / death_time)).y);
		dead_splash->set_frame(0);
		dead_splash->set_alpha(to_alpha);
		dead_splash->set_scale(to_scale,to_scale);
		dead_splash->set_alignment(origin_center);
		dead_splash->draw(gc, prev_position.x, prev_position.y);
	}
	if (player_time > death_time)
	{
		if (spellcard)
			spellcard = 0;
		if (invicible)
			player_sprite.set_alpha((float)(100 + invicible%100) / 200.f);
		else
			player_sprite.set_alpha(1);
		// Определить кадр спрайта исходя из движения
		float anim_speed = 100.0f;
		if (moving_aside)
		{
			if (sidemove_time > anim_speed * 4.0f)
			{
				// стабилизировавшееся движение
				if (moving_aside < 0)
					player_sprite.set_frame(12 + (int)(player_time / anim_speed) % 4);
				else
					player_sprite.set_frame(20 + (int)(player_time / anim_speed) % 4);
			}
			else
			{
				// фаза разворота в сторону
				if (moving_aside < 0)
					player_sprite.set_frame(8 + (int)(sidemove_time / anim_speed));
				else
					player_sprite.set_frame(16 + (int)(sidemove_time / anim_speed));
			}
		}
		else
		{
			sidemove_time = 0;
			player_sprite.set_frame((int)(player_time / anim_speed) % 8);
		}
		player_sprite.set_angle(CL_Angle(0,cl_degrees));
		player_sprite.set_alignment(origin_center);
		player_sprite.draw(gc, position.x, position.y);
		float focus_alpha;
		if (!spellcard_activated && (focused || focused_time))
		{
			if (!focused || (focused && (focused_time < 200)))
				focus_alpha = focused_time / 200.0f;
			else
				focus_alpha = 1.0f;
			focus_sprite.set_frame(0);
			focus_sprite.set_alpha(focus_alpha);
			CL_Angle focus_angle;
			focus_angle.set_degrees((float)(((int)player_time%3600)/10));
			focus_sprite.set_angle(focus_angle);
			focus_sprite.set_alignment(origin_center);
			focus_sprite.draw(gc, position.x, position.y);
		}
		// Значение энергии ветра над головой
		if (wind > 100)
			wind = 100;
		float walpha = 0.6f;
		float wfscale = 0.7f;
		if (wind < 30)
		{
			wfscale = 0.5f;
		}
		float whpos = -28.0f - 9.0f * wfscale;
		float wspos;
		if (wind == 100)
			wspos = 29.5f * wfscale;
		else if (wind > 9)
			wspos = 22.5f * wfscale;
		else
			wspos = 15.5f * wfscale;
		wind_font_sprite.set_alignment(origin_center);
		wind_font_sprite.set_scale(wfscale, wfscale);
		wind_font_sprite.set_alpha(walpha);
		wind_font_sprite.set_frame(10);
		wind_font_sprite.draw(gc, position.x + wspos, position.y + whpos);
		wspos -= 14.0f;
		int wind_draw = wind;
		while (wind_draw > 0)
		{
			int wi = wind_draw % 10;
			wind_font_sprite.set_frame(wi);
			wind_font_sprite.draw(gc, position.x + wspos, position.y + whpos);
			wspos -= 14.0f * wfscale;
			wind_draw /= 10;
		}
	}
	gc.pop_cliprect();
}

// Эффекты на заднем фоне - пентаграммы и пр.
void Player::RenderBack(CL_GraphicContext &gc, RingSprite* ring_renderer)
{
	gc.set_cliprect(global_state.clip_rect);
	float const_alpha = 0.7f;
	// Бомба
	if (is_bomb)
	{
		// затенение
		float a = 0.3f;
		if (bomb_time < 100.0f)
			a = bomb_time / 300.0f;
		if ((bomb_duration - bomb_time) < 100.0f)
			a = (bomb_duration - bomb_time) / 300.0f;
		CL_Sprite* mask = sprite_container.GetSprite("screen_mask");
		CL_Sprite* gust = sprite_container.GetSprite("wind_gust");
		mask->set_frame(0);
		mask->set_alpha(a);
		mask->set_scale(640.0f, 480.0f);
		mask->set_linear_filter(false);
		mask->draw(gc, 0, 0);
		// потоки ветра
		gust->set_alpha(0.9f);
		gust->set_scale(2.0f, 2.5f);
		gust->draw(gc, 50, (int)(bomb_duration - bomb_time) % 600 - 128);
		gust->draw(gc, 120, (int)(55 + bomb_duration - bomb_time) % 622 - 128);
		gust->draw(gc, 130, (int)((500.0f + bomb_duration - bomb_time) * 1.2f) % 870 - 128);
		gust->draw(gc, 321, (int)(bomb_duration - bomb_time) % 610 - 128);
		gust->draw(gc, 250, (int)(115 + bomb_duration - bomb_time) % 721 - 128);
		gust->draw(gc, 400, (int)(240 + bomb_duration - bomb_time) % 670 - 128);
		gust->draw(gc, 80, (int)(260 + bomb_duration - bomb_time) % 690 - 128);
		gust->draw(gc, 190, (int)((300.0f + bomb_duration - bomb_time) * 1.1f) % 870 - 128);
		// сдувать снежинки с фона
		background.bomb_blow();
	}
	// Эффект воздушного кольца
	if (wind_activated)
	{
		float s = 1.0f;
		float a = 1.0f;
		if (wind_blow_time < 50.0f)
			s = 0.3f + wind_blow_time / 71.4f;
		if (wind_to_blow < 50.0f)
			a = wind_to_blow / 50.0f;
		wind_sprite.set_scale(s * wind_current_radius / wind_radius, s * wind_current_radius / wind_radius);
		wind_sprite.set_alpha(a);
		wind_sprite.set_alignment(origin_center);
		wind_sprite.set_angle(CL_Angle(wind_blow_time, cl_degrees));
		wind_sprite.draw(gc, player.prev_position.x, player.prev_position.y);
		background.player_blow();
	}
	else if (shot_gaining > time_to_activate_wind)
	{
		// набор ветра
		if (shot_gaining < (time_to_activate_wind + time_wind_activation))
		{
			// заряженный ветер
			wind_sprite.set_alpha((shot_gaining - time_to_activate_wind) / time_wind_activation);
			wind_sprite.set_scale(0.5f, 0.5f);
			wind_sprite.set_alignment(origin_center);
			wind_sprite.set_angle(CL_Angle(shot_gaining * 2.0f, cl_degrees));
			wind_sprite.draw(gc, player.prev_position.x, player.prev_position.y);
			// индикатор набора ветра
			float l = 32.0f * (shot_gaining - time_to_activate_wind) / time_wind_activation;
			CL_Colorf c(1.0f, 1.0f, 0.7f, 0.7f);
			CL_Colorf c1(0.2f, 0.2f, 0.1f, 0.7f);
			CL_Draw::line(gc, player.position.x - 16.0f, player.position.y + 24.0f, l + player.position.x - 16.0f, player.position.y + 24.0f, c);
			CL_Draw::line(gc, player.position.x - 16.0f, player.position.y + 25.0f, l + player.position.x - 16.0f, player.position.y + 25.0f, c);
			CL_Draw::line(gc, player.position.x - 16.0f, player.position.y + 26.0f, l + player.position.x - 16.0f, player.position.y + 26.0f, c);
			CL_Draw::line(gc, player.position.x - 16.0f, player.position.y + 27.0f, l + player.position.x - 16.0f, player.position.y + 27.0f, c);
		}
		else
		{
			// заряженный ветер
			wind_sprite.set_alpha(1.0f);
			wind_sprite.set_scale(0.5f, 0.5f);
			wind_sprite.set_alignment(origin_center);
			wind_sprite.set_angle(CL_Angle(shot_gaining * 2.0f, cl_degrees));
			wind_sprite.draw(gc, player.prev_position.x, player.prev_position.y);
		}
	}
	gc.pop_cliprect();
}

// Стрельба
void Player::Shoot(int bullet_type)
{
	switch (bullet_type)
	{
	case 0:
		// пустить паттерн выстрела
		patterns.LaunchPattern(position, 100000001, dummy_player);
		break;
	case 2:
		// Пустить автопули спеллкарты "Перекрестье"
		patterns.LaunchPattern(position, 100000005, dummy_player);
		break;
	}
}


// Ввод игрока
void Player::AttachInput(CL_DisplayWindow &window)
{
	keyboard = window.get_ic().get_keyboard();
	slots.connect(window.get_ic().get_keyboard().sig_key_down(), this, &Player::on_key_down);
	slots.connect(window.get_ic().get_keyboard().sig_key_up(), this, &Player::on_key_up);
	if(window.get_ic().get_joystick_count() > 0)
	{
		joystick_available = true;
		joystick = window.get_ic().get_joystick();
		slots.connect(window.get_ic().get_joystick().sig_axis_move(), this, &Player::on_joystick_axis_move);
		slots.connect(window.get_ic().get_joystick().sig_key_down(), this, &Player::on_joystick_key_down);
		slots.connect(window.get_ic().get_joystick().sig_key_up(), this, &Player::on_joystick_key_up);
	}
}

void Player::on_key_down(const CL_InputEvent &key, const CL_InputState &state)
{
	if (key.id == CL_KEY_RIGHT)
	{
		last_key_right = 1;
		last_key_left = 0;
	}
	if (key.id == CL_KEY_LEFT)
	{
		last_key_right = 0;
		last_key_left = 1;
	}
	if (key.id == CL_KEY_UP)
	{
		last_key_up = 1;
		last_key_down = 0;
	}
	if (key.id == CL_KEY_DOWN)
	{
		last_key_up = 0;
		last_key_down = 1;
	}
}

void Player::on_key_up(const CL_InputEvent &key, const CL_InputState &state)
{
}

void Player::on_joystick_axis_move(const CL_InputEvent &joy, const CL_InputState &state)
{
	joystick_moved = 1;
}

void Player::on_joystick_key_down(const CL_InputEvent &joy, const CL_InputState &state)
{
	joystick_moved = 1;
}

void Player::on_joystick_key_up(const CL_InputEvent &joy, const CL_InputState &state)
{
}


void Player::process_keyboard()
{
	int temp_key = 0;
	if (keyboard.get_keycode(CL_KEY_RIGHT))
	{
		direction.x = 1;
		temp_key = 1;
	}
	if (keyboard.get_keycode(CL_KEY_LEFT))
	{
		if (temp_key)
		{
			if (last_key_left)
				direction.x = -1;
		}
		else
			direction.x = -1;
	}
	temp_key = 0;
	if (keyboard.get_keycode(CL_KEY_UP))
	{
		direction.y = -1;
		temp_key = 1;
	}
	if (keyboard.get_keycode(CL_KEY_DOWN))
	{
		if (temp_key)
		{
			if (last_key_down)
				direction.y = 1;
		}
		else
			direction.y = 1;
	}
	// Немного убавим скорость, если движение по диагонали, для реалистичности
	if (abs(direction.x) && abs(direction.y))
	{
		direction.x *= 0.8f;
		direction.y *= 0.8f;
	}
	if (keyboard.get_keycode(CL_KEY_LSHIFT))
		focused = true;
	if (keyboard.get_keycode(CL_KEY_Z))
	{
		shooting = true;
	}
	if (keyboard.get_keycode(CL_KEY_C) || keyboard.get_keycode(CL_KEY_LCONTROL))
	{
		rapid = true;
		if (global_state.shotslow)
			focused = true;
	}
	if (keyboard.get_keycode(CL_KEY_X))
	{
		if (!is_bomb)
			bomb_trigger = true;
	}
}

void Player::process_joystick()
{
	if (!joystick_moved)
		return;
	// Стик
	float axis_x = (float)joystick.get_axis(0);
	float axis_y = (float)joystick.get_axis(1);
	if (axis_x < -(global_state.axis_sens))
	{
		direction.x = -1;
	}
	if (axis_x > global_state.axis_sens)
	{
		direction.x = 1;
	}
	if (axis_y < -(global_state.axis_sens))
	{
		direction.y = -1;
	}
	if (axis_y > global_state.axis_sens)
	{
		direction.y = 1;
	}
	// D-Pad
	double dpad = joystick.get_axis(32);
	if (dpad == 0) // вверх
	{
		direction.x = 0;
		direction.y = -1;
	}
	if (dpad == 4500) // вправо-вверх
	{
		direction.x = 1;
		direction.y = -1;
	}
	if (dpad == 9000) // вправо
	{
		direction.x = 1;
		direction.y = 0;
	}
	if (dpad == 13500) // вправо-вниз
	{
		direction.x = 1;
		direction.y = 1;
	}
	if (dpad == 18000) // вниз
	{
		direction.x = 0;
		direction.y = 1;
	}
	if (dpad == 22500) // влево-вниз
	{
		direction.x = -1;
		direction.y = 1;
	}
	if (dpad == 27000) // влево
	{
		direction.x = -1;
		direction.y = 0;
	}
	if (dpad == 31500) // влево-вверх
	{
		direction.x = -1;
		direction.y = -1;
	}

	// Немного убавим скорость, если движение по диагонали, для реалистичности
	if (abs(direction.x) && abs(direction.y))
	{
		direction.x *= 0.8f;
		direction.y *= 0.8f;
	}

	// Кнопки джоя
	if (joystick.get_keycode(global_state.key_focus))
		focused = true;
	if (joystick.get_keycode(global_state.key_fire))
	{
		shooting = true;
	}
	if (joystick.get_keycode(global_state.key_bomb))
	{
		if (!is_bomb)
			bomb_trigger = true;
	}
	// rapid fire
	if (joystick.get_keycode(global_state.key_spell))
	{
		rapid = true;
		if (global_state.shotslow)
			focused = true;
	}
}

void Player::Reset(int power_reset)
{
	score = 0;
	points = 0;
	graze = 0;
	if (power_reset)
		power = power / 2;
	else
		power = start_power;
	spells = 2;
	spellcard_activated = false;
	dead = false;
	player_time = 0;
	dead_time = 0;
	wind_activated = false;
	wind_time = 0;
	is_bomb = false;
	bomb_time = 0;
}

void Player::DropBonus()
{
	int power_drop = power / 2;
	power -= power_drop;
	Bonus b;
	b.bonus_type = 3;
	if (power_drop >= 8)
	{
		b.position = position;
		b.position.y -= 20.0f;
		b.prev_position = b.position;
		b.speed = -0.115f;
		b.move = CL_Vec2f(0, -0.115f);
		power_drop -= 8;
		bonus_manager.Add(b);
	}
	if (power_drop >= 8)
	{
		b.position = position;
		b.position.y -= 15.0f;
		b.position.x += 20.0f;
		b.prev_position = b.position;
		b.speed = -0.115f;
		b.move = CL_Vec2f(0.015f, -0.112f);
		power_drop -= 8;
		bonus_manager.Add(b);
	}
	if (power_drop >= 8)
	{
		b.position = position;
		b.position.y -= 15.0f;
		b.position.x -= 20.0f;
		b.prev_position = b.position;
		b.speed = -0.115f;
		b.move = CL_Vec2f(-0.015f, -0.112f);
		power_drop -= 8;
		bonus_manager.Add(b);
	}
	if (power_drop >= 8)
	{
		b.position = position;
		b.position.x += 40.0f;
		b.prev_position = b.position;
		b.speed = -0.11f;
		b.move = CL_Vec2f(0.02f, -0.11f);
		power_drop -= 8;
		bonus_manager.Add(b);
	}
	if (power_drop >= 8)
	{
		b.position = position;
		b.position.x -= 40.0f;
		b.prev_position = b.position;
		b.speed = -0.11f;
		b.move = CL_Vec2f(-0.02, -0.11f);
		power_drop -= 8;
		bonus_manager.Add(b);
	}
	b.bonus_type = 0;
	if (power_drop > 0)
	{
		b.position = position;
		b.position.y -= 17.0f;
		b.position.x += 10.0f;
		b.prev_position = b.position;
		b.speed = -0.12f;
		b.move = CL_Vec2f(0.012f, -0.12f);
		power_drop--;
		bonus_manager.Add(b);
	}
	if (power_drop > 0)
	{
		b.position = position;
		b.position.y -= 17.0f;
		b.position.x -= 10.0f;
		b.prev_position = b.position;
		b.speed = -0.12f;
		b.move = CL_Vec2f(-0.012f, -0.12f);
		power_drop--;
		bonus_manager.Add(b);
	}
	if (power_drop > 0)
	{
		b.position = position;
		b.position.y -= 5.0f;
		b.position.x += 30.0f;
		b.prev_position = b.position;
		b.speed = -0.115f;
		b.move = CL_Vec2f(0.017f, -0.115f);
		power_drop--;
		bonus_manager.Add(b);
	}
	if (power_drop > 0)
	{
		b.position = position;
		b.position.y -= 5.0f;
		b.position.x -= 30.0f;
		b.prev_position = b.position;
		b.speed = -0.115f;
		b.move = CL_Vec2f(-0.017f, -0.115f);
		power_drop--;
		bonus_manager.Add(b);
	}
}
